﻿/* EntitiesToDTOs. Copyright (c) 2011. Fabian Fernandez.
 * http://entitiestodtos.codeplex.com
 * Licensed by Common Development and Distribution License (CDDL).
 * http://entitiestodtos.codeplex.com/license
 * Fabian Fernandez. 
 * http://www.linkedin.com/in/fabianfernandezb/en
 * */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using EntitiesToDTOs.Properties;
using EntitiesToDTOs.Enums;
using EntitiesToDTOs.Helpers;

namespace EntitiesToDTOs.Domain
{
    /// <summary>
    /// Represents an Entity Navigation.
    /// </summary>
    internal class EntityNavigation
    {
        /// <summary>
        /// DTO Name (Owner of the Navigations).
        /// </summary>
        public string DTOName { get; private set; }

        /// <summary>
        /// Navigation property name found in the EDMX.
        /// </summary>
        public string NavigationPropertyNameEDMX { get; private set; }

        /// <summary>
        /// List of Navigation Properties.
        /// </summary>
        public List<EntityNavigationProperty> NavigationProperties { get; set; }


        public EntityNavigation(XElement navigationNode, List<EntityAssociation> entitiesAssociations,
            string associationTypeDesired, List<EntityKeyProperty> entitiesKeys)
        {
            // Set DTO Name
            string entityName = navigationNode.Parent.Attribute(EdmxNodeAttributes.EntityType_Name).Value;
            this.DTOName = EntityDTOHelper.GetDTOName(entityName);

            // Get the To Role End name
            string toRole = navigationNode.Attribute(EdmxNodeAttributes.NavigationProperty_ToRole).Value;

            // Get the Association Name
            string associationName = navigationNode.Attribute(EdmxNodeAttributes.NavigationProperty_Relationship).Value;
            string[] associationNameSplitted = associationName.Split(new string[] { Resources.Dot }, StringSplitOptions.RemoveEmptyEntries);
            associationName = associationNameSplitted[(associationNameSplitted.Length - 1)];

            this.NavigationProperties = new List<EntityNavigationProperty>();

            // Find the Association
            EntityAssociation association = (
                from a in entitiesAssociations
                where (a.AssociationName == associationName) && (a.EndRoleName == toRole)
                select a
                ).FirstOrDefault();

            // Find the DTO associated keys
            IEnumerable<EntityKeyProperty> dtoToKeys = entitiesKeys.Where(k => k.DTOName == association.DTOName);

            // Get the base Property Name
            this.NavigationPropertyNameEDMX = navigationNode.Attribute(EdmxNodeAttributes.NavigationProperty_Name).Value;
            string propertyName = PropertyHelper.GetPropertyName(this.NavigationPropertyNameEDMX, entityName);
            // TODO: ffernandez, remove below commented code
            //if (propertyName.Contains(Resources.NameEntitySet))
            //{
            //    propertyName = propertyName.Remove(
            //        propertyName.IndexOf(Resources.NameEntitySet), Resources.NameEntitySet.Length);
            //}
            //else if (propertyName.Contains(Resources.NameEntity))
            //{
            //    propertyName = propertyName.Remove(
            //        propertyName.IndexOf(Resources.NameEntity), Resources.NameEntity.Length);
            //}

            if (association.EndMultiplicity == EntityAssociationMultiplicityEnum.Many)
            {
                if ((associationTypeDesired != AssociationTypeEnum.ClassType) 
                    && (dtoToKeys.Count() != 1))
                {
                    WarningsPool.AddWarning(string.Format(Resources.Warning_CannotCreateNavPropManyKeyProp, 
                        this.DTOName, association.DTOName));

                    associationTypeDesired = AssociationTypeEnum.ClassType;
                }

                if (propertyName.EndsWith(Resources.NameTailPlural) == false)
                {
                    propertyName += Resources.NameTailPlural; // pluralize name
                    // TODO: ffernandez, review pluralize thing...
                }

                bool isList = true;

                if (associationTypeDesired == AssociationTypeEnum.ClassType)
                {
                    // List<T> Type
                    string type = string.Format(Resources.CSharpTypeListT, association.DTOName);

                    this.NavigationProperties.Add(new EntityNavigationProperty(type, propertyName, isList, association.DTOName, association.DTOName));
                }
                else
                {
                    // AssociationTypeEnum.KeyProperty
                    EntityKeyProperty dtoToKey = dtoToKeys.First();
                    
                    // List<T> Type
                    string type = string.Format(Resources.CSharpTypeListT, dtoToKey.Type);

                    propertyName += (Resources.NameSeparator + dtoToKey.Name);

                    this.NavigationProperties.Add(new EntityNavigationProperty(type, propertyName, isList, dtoToKey.Type, association.DTOName));
                }
            }
            else
            {
                // EntityAssociationMultiplicityEnum.One
                // EntityAssociationMultiplicityEnum.ZeroOrOne
                bool isList = false;
                string listOf = null;

                if (associationTypeDesired == AssociationTypeEnum.ClassType)
                {
                    this.NavigationProperties.Add(new EntityNavigationProperty(association.DTOName, propertyName, isList, listOf, association.DTOName));
                }
                else
                {
                    // AssociationTypeEnum.KeyProperty

                    foreach (EntityKeyProperty dtoToKey in dtoToKeys)
                    {
                        string propName = (propertyName + Resources.NameSeparator + dtoToKey.Name);

                        this.NavigationProperties.Add(new EntityNavigationProperty(dtoToKey.Type, propName, isList, listOf, association.DTOName));
                    }
                }
            }
        }
    }
}